#include "../include/Vector.h"
#include <cassert>
#include <cmath>

Vector::Vector(int dim)
{
    assert(dim > 0);
    nDim = dim;
    m_type = LINEVECTOR;
    data = new float[nDim];
    for(int i = 0; i < nDim; ++i)
        data[i] = 0.0;
}
Vector::Vector(const Vector& v)
{
    nDim = v.dim();
    m_type = v.type();
    data = new float[nDim];
    for(int i = 0; i < nDim; ++i)
        data[i] = v(i);
}

Vector::~Vector()
{
    delete [] data;
}

float& Vector::operator()(int idx)
{
    assert(idx >= 0 && idx < nDim);
    return data[idx];
}

const float Vector::operator()(int idx)const
{
    assert(idx >= 0 && idx < nDim);
    return data[idx];
}

Vector Vector::operator+(const Vector& v)const
{
    assert(v.dim() == dim() && v.type() == type());
    Vector resp(dim());
    for(int i=0; i < dim(); ++i)
        resp(i) = data[i] + v(i);

    return v.type() == COLUMNVECTOR? resp.transpose() : resp;
}
Vector Vector::operator-(const Vector& v)const
{
    assert(v.dim() == dim() && v.type() == type());
    Vector resp(dim());
    for(int i=0; i < dim(); ++i)
        resp(i) = data[i] - v(i);

    return v.type() == COLUMNVECTOR? resp.transpose() : resp;
}
Vector Vector::operator-()const
{
    Vector resp(dim());
    for(int i=0; i < dim(); ++i)
        resp(i) = -data[i];

    return type() == COLUMNVECTOR? resp.transpose() : resp;
}
float Vector::operator*(const Vector& v)const
{
    assert(type() == LINEVECTOR && v.type() == COLUMNVECTOR);
    return Vector::dot(*this, v);
}

Vector Vector::operator*(float a)const
{
    Vector resp(dim());
    for(int i=0; i < dim(); ++i)
        resp(i) = data[i]*a;

    return type() == COLUMNVECTOR? resp.transpose() : resp;
}
Vector Vector::operator/(float a)const
{
    Vector resp(dim());
    for(int i=0; i < dim(); ++i)
        resp(i) = data[i]/a;

    return resp;
}
Vector operator*(float a, const Vector& v)
{
    return v*a;
}
const Vector& Vector::operator=(const Vector& v)
{
    if(dim() != v.dim())
    {
        delete [] data;
        nDim = v.dim();
        data = new float[nDim];
    }

    for(int i = 0; i < nDim; ++i)
        data[i] = v(i);

    m_type = v.type();

    return *this;
}

void Vector::swap(int i, int j)
{
    float t = data[i];
    data[i] = data[j];
    data[j] = t;
}

const int Vector::dim()const
{
    return nDim;
}

TypeVector Vector::type()const
{
    return m_type;
}
const Vector&  Vector::transpose()
{
    m_type = (m_type == LINEVECTOR?COLUMNVECTOR:LINEVECTOR);

    return *this;
}

float Vector::length ()
{
    return sqrtf(dot(*this,*this));
}

std::ostream& operator<<(std::ostream& out, const Vector& v)
{
    out << (v.type() == LINEVECTOR? "L" : "C" ) << "::[";
    for(int i = 0; i < v.dim()-1; ++i)
        out << "\t" << v(i) << ",";
    out << "\t" << v(v.dim()-1) << "\t]";
    return out;
}

float Vector::dot(const Vector& v1, const Vector& v2)
{
    assert(v1.dim() == v2.dim());
    float r = 0.0;
    for(int i = 0; i < v1.dim(); ++i)
        r+= v1(i)*v2(i);
    return r;
}

void Vector::set(float * d)
{
    for(int i = 0; i < dim(); ++i)
        data[i] = d[i];
}

void Vector::set(float v)
{
    for(int i = 0; i < dim(); ++i)
        data[i] = v;
}
